/*
 *  world.cc
 *  wonderland-project
 *
 *  Created by Ben Nolan on 14/10/08.
 *  Copyright 2008 Nolan Consulting Limited. All rights reserved.
 *
 */

#include <v8.h>
#include <Ogre.h>
#include "world.h"
#include "node.h"
#include "entity.h"
#include "skeleton.h"
#include "vector.h"
#include "v8defines.h"
#include "region.h"
#include "scripting_context.h"

namespace JSWorld{
  Wonderland::Region *region_;
  
  v8::Handle<v8::ObjectTemplate> instance_template;
  v8::Handle<v8::FunctionTemplate> function_template;
  v8::Persistent<v8::Context> context_;

  V8CALLBACK(World,createNode){
    char name[50];
    sprintf(name, "/Node/%08x", rand() % 0xFFFFFFFF);

    Ogre::SceneNode *node = region_->createNode(name);

    return JSNode::New(node);
  }

  V8CALLBACK(World,createEntity){
    if(args.Length()!=1)
      return ThrowException(v8::String::New("Invalid argument"));

    v8::String::Utf8Value filename(args[0]);

    char name[50];
    sprintf(name, "/Entity/%08x", rand() % 0xFFFFFFFF);

    Ogre::Entity *ent = region_->getSceneManager()->createEntity(std::string(name), *filename);
    
    return JSEntity::New(ent);
  }

  V8CALLBACK(World,getNodeById){ 
    if(args.Length()!=1)
      return ThrowException(v8::String::New("Invalid argument"));

    v8::String::Utf8Value id(args[0]);

    if(!region_->getSceneManager()->hasSceneNode(*id)){
      return v8::Null();
    }
    
    return(JSNode::New(region_->getSceneManager()->getSceneNode(*id)));
  }

  V8CALLBACK(World,getNearby){ 
    return ThrowException(v8::String::New("Unimplemented"));

    /* Find the nearest elements to the supplied vector */
    
//    if (!V8ARGUMENTTYPE("Vector", 0))
//      return ThrowException(v8::String::New("Invalid argument"));
//
//    *V8ARGUMENT(Ogre::Vector3*, 0)
//
//    int children = scene_manager_->getRootSceneNode()->numChildren();
//    v8::Handle<v8::Array> result_array = v8::Array::New(children); 
//
//    for(int i=0;i<children;i++){
//      result_array->Set(v8::Number::New(i), JSNode::New((Ogre::SceneNode *)scene_manager_->getRootSceneNode()->getChild(i)));
//    }
//    
//    return result_array;
  }
  
  /* Construct a new instance */
  V8CALLBACK(World,create){
    v8::Persistent<v8::Object> self = v8::Persistent<v8::Object>::New(args.Holder());
    return self;
  }

  /* Called from c++ */
  v8::Handle<v8::Value> New(Wonderland::Region* region){
    context_->Enter();

    region_ = region;
    
    return v8::Persistent<v8::Object>::New(function_template->GetFunction()->NewInstance());
  }

  void Initialize(Wonderland::ScriptingContext *sc){
    context_ = sc->getContext();

    // Function Template
    function_template = v8::FunctionTemplate::New(World_create);
    function_template->SetClassName(v8::String::New("World"));

    // Instance template
    instance_template = function_template->InstanceTemplate();
    instance_template->SetInternalFieldCount(2);

    #define V8REGISTER(function) instance_template->Set(#function, v8::FunctionTemplate::New(World_ ## function));
    
    V8REGISTER(createNode);
    V8REGISTER(createEntity);
    V8REGISTER(getNodeById);

    // No constructor - since you can't create these via "new"
  }

}

